#include "Map.h"
#include <iostream>
#include <fstream>
#include <list>

using namespace std;

Map::Map()
{
	fields = 0;
	rows = 0;
	columns = 0;
	highest = 0.0f;
}
Map::~Map()
{
	delete[] fields;
	fields = 0;
	rows = 0;
	columns = 0;
}

int Map::Columns(void)
{
	return columns;
}
int Map::Rows(void)
{
	return rows;
}
Box* Map::Fields(void)
{
	return fields;
}

bool Map::Load(wchar_t *fileName, Map *map)
{		
	ifstream input(fileName);	
	if(!input)
		return false;
	
	//while loading the map size is unknown, so we'll load it to lists
	list<float> columnHeights;
	list<list<float>> rowHeights;
	

	//Get file size
	input.seekg(0, ios::end);
	int size = input.tellg();
	input.seekg(0, ios::beg);

	//Load entire file to buffer
	char* fileBuffer = new char[size + 1];		
	

	//extract numbers from buffer
	int startIndex;	
	bool isFirstRaw = true;
	int columns = 0;
	int lineLength;
	char c;
	float height;
	while(!input.eof())
	{
		input.getline(fileBuffer, size + 1);			
		lineLength = (int)strlen(fileBuffer);
		startIndex = 0;
		for(int i = 0; i <= lineLength; i++)
		{
		
			if(fileBuffer[i] == ' ' || fileBuffer[i] == ',' || fileBuffer[i] == ';' || fileBuffer[i] == 0)
			{
				columns++;			
				c = fileBuffer[i];
				fileBuffer[i] = 0;
				height = (float)atof(fileBuffer + startIndex);
				if(height < 0.0f)
					height = 0.0f;
				columnHeights.push_back(height);
				if(height > map->highest)
					map->highest = height;
				startIndex = i + 1;			
				fileBuffer[i] = c;
			
				if(fileBuffer[i] == 0)
				{
					if(isFirstRaw)
					{
						isFirstRaw = false;
						map->columns = columns;				
					}
					else
					{
						if(columns != map->columns)
						{
							input.close();
							delete[] fileBuffer;						
							return false;
						}
					}
					rowHeights.push_back(columnHeights);
					columnHeights.clear();
					columns = 0;				
				}
			}			
		}
	}
	input.close();
	delete[] fileBuffer;
	map->rows = (int)rowHeights.size();
	map->fields = new Box[map->columns * map->rows];
	int x, y = 0;
	for(list<list<float>>::iterator row = rowHeights.begin(); row != rowHeights.end(); ++row)
	{
		x = 0;
		for(list<float>::iterator column = row->begin(); column != row->end(); ++column)
		{
			map->Field(x, y).SetHeight(*column);
			map->Field(x, y).SetX(x + 0.5f);
			map->Field(x, y).SetY(y + 0.5f);
			x++;
		}
		y++;
	}
	return true;
}

Box& Map::Field(int x, int y)
{
	return fields[y * columns + x];
}

void Map::SetField(int x, int y, Box& box)
{
	fields[y * columns + x] = box;
}

float Map::GetHighest(void)
{
	return highest;
}